﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Json;
using System.Web.Script.Serialization;
using System.Xml;

namespace fbasync
{
    public partial class FacebookConnection
    {
        #region Dashboard Api

        #region Single Counters

        public event EventHandler<AsyncCompletedEventArgs<int>> GetCountCompleted;

        public void GetCountAsync(long uid, object userState)
        {
            AsyncOperation op = AsyncOperationManager.CreateOperation(userState);
            IAsyncResult opAr = BeginGetCount(
                uid,
                (ar) => { SetupAsyncCompletion<Int32State, int>(ar, EndGetCount, OnGetCountCompleted); },
                op);
        }

        protected virtual void OnGetCountCompleted(object sender, AsyncCompletedEventArgs<int> e)
        {
            var eh = GetCountCompleted;

            if (null != eh)
                eh(sender, e);
        }

        public IAsyncResult BeginGetCount(AsyncCallback callback, object state)
        {
            AssertUserId();
            return BeginGetCount(UserId.Value, callback, state);
        }

        public IAsyncResult BeginGetCount(long uid, AsyncCallback callback, object state)
        {
            var args = new Dictionary<string, string>();
            args.Add("uid", uid.ToString());

            LazyAsyncResult<Int32State> myAr = new LazyAsyncResult<Int32State>(new Int32State(), callback, state);
            BeginExecuteApiCall(@"dashboard.getCount", args, false, false, Int32StateCallback, myAr);
            return myAr;
        }

        public int EndGetCount(IAsyncResult ar)
        {
            return ar.End<Int32State>().Result;
        }

        public event EventHandler<AsyncCompletedEventArgs> SetCountCompleted;

        public void SetCountAsync(long uid, int count, object userState)
        {
            AsyncOperation op = AsyncOperationManager.CreateOperation(userState);
            IAsyncResult opAr = BeginSetCount(
                uid,
                count,
                (ar) => { SetupAsyncCompletion<object>(ar, EndSetCount, OnSetCountCompleted); },
                op);
        }

        protected virtual void OnSetCountCompleted(object sender, AsyncCompletedEventArgs e)
        {
            var eh = SetCountCompleted;

            if (null != eh)
                eh(sender, e);
        }

        public IAsyncResult BeginSetCount(int count, AsyncCallback callback, object state)
        {
            AssertUserId();
            return BeginSetCount(UserId.Value, count, callback, state);
        }

        public IAsyncResult BeginSetCount(long uid, int count, AsyncCallback callback, object state)
        {
            var args = new Dictionary<string, string>();
            args.Add("uid", uid.ToString());
            args.Add("count", count.ToString());

            LazyAsyncResult<object> myAr = new LazyAsyncResult<object>(callback, state);
            BeginExecuteApiCall(@"dashboard.setCount", args, false, false, ObjectStateCallback, myAr);
            return myAr;
        }

        public void EndSetCount(IAsyncResult ar)
        {
            ar.End<object>();
        }

        public event EventHandler<AsyncCompletedEventArgs> IncrementCountCompleted;

        public void IncrementCountAsync(long uid, object userState)
        {
            AsyncOperation op = AsyncOperationManager.CreateOperation(userState);
            IAsyncResult opAr = BeginIncrementCount(
                uid,
                (ar) => { SetupAsyncCompletion<object>(ar, EndIncrementCount, OnIncrementCountCompleted); },
                op);
        }

        protected virtual void OnIncrementCountCompleted(object sender, AsyncCompletedEventArgs e)
        {
            var eh = IncrementCountCompleted;

            if (null != eh)
                eh(sender, e);
        }

        public IAsyncResult BeginIncrementCount(AsyncCallback callback, object state)
        {
            AssertUserId();
            return BeginIncrementCount(UserId.Value, callback, state);
        }

        public IAsyncResult BeginIncrementCount(long uid, AsyncCallback callback, object state)
        {
            var args = new Dictionary<string, string>();
            args.Add("uid", uid.ToString());

            LazyAsyncResult<object> myAr = new LazyAsyncResult<object>(callback, state);
            BeginExecuteApiCall(@"dashboard.incrementCount", args, false, false, ObjectStateCallback, myAr);
            return myAr;
        }

        public void EndIncrementCount(IAsyncResult ar)
        {
            ar.End<object>();
        }

        public event EventHandler<AsyncCompletedEventArgs> DecrementCountCompleted;

        public void DecrementCountAsync(long uid, object userState)
        {
            AsyncOperation op = AsyncOperationManager.CreateOperation(userState);
            IAsyncResult opAr = BeginDecrementCount(
                uid,
                (ar) => { SetupAsyncCompletion<object>(ar, EndDecrementCount, OnDecrementCountCompleted); },
                op);
        }

        protected virtual void OnDecrementCountCompleted(object sender, AsyncCompletedEventArgs e)
        {
            var eh = DecrementCountCompleted;

            if (null != eh)
                eh(sender, e);
        }

        public IAsyncResult BeginDecrementCount(AsyncCallback callback, object state)
        {
            AssertUserId();
            return BeginDecrementCount(UserId.Value, callback, state);
        }

        public IAsyncResult BeginDecrementCount(long uid, AsyncCallback callback, object state)
        {
            var args = new Dictionary<string, string>();
            args.Add("uid", uid.ToString());

            LazyAsyncResult<object> myAr = new LazyAsyncResult<object>(callback, state);
            BeginExecuteApiCall(@"dashboard.decrementCount", args, false, false, ObjectStateCallback, myAr);
            return myAr;
        }

        public void EndDecrementCount(IAsyncResult ar)
        {
            ar.End<object>();
        }

        #endregion

        #region MultiCounters

        public event EventHandler<AsyncCompletedEventArgs<Dictionary<long, int>>> MultiGetCountCompleted;

        public void MultiGetCountAsync(IEnumerable<long> uids, object userState)
        {
            AsyncOperation op = AsyncOperationManager.CreateOperation(userState);
            IAsyncResult opAr = BeginMultiGetCount(
                uids,
                (ar) => { SetupAsyncCompletion<Dictionary<long, int>, Dictionary<long, int>>(ar, EndMultiGetCount, OnMultiGetCountCompleted); },
                op);
        }

        protected virtual void OnMultiGetCountCompleted(object sender, AsyncCompletedEventArgs<Dictionary<long, int>> e)
        {
            var eh = MultiGetCountCompleted;

            if (null != eh)
                eh(sender, e);
        }

        public IAsyncResult BeginMultiGetCount(IEnumerable<long> uids, AsyncCallback callback, object state)
        {
            if (uids == null) throw new ArgumentNullException("uids");

            var args = new Dictionary<string, string>();
            args.Add("uids", '[' + string.Join(",", uids.Select(u => u.ToString()).ToArray()) + ']');

            var myAr = new LazyAsyncResult<Dictionary<long, int>>(null, callback, state);
            BeginExecuteApiCall(
                @"dashboard.multiGetCount", args, false, false,
                SafeXmlDeserializeCallback<Schema.Dashboard.MultiGetCountResponse, Dictionary<long, int>>(resp => resp.Elements.ToDictionary(e => e.Key, e => e.Value)),
                myAr);
            return myAr;
        }

        public Dictionary<long, int> EndMultiGetCount(IAsyncResult ar)
        {
            return ar.End<Dictionary<long, int>>();
        }

        public event EventHandler<AsyncCompletedEventArgs<Dictionary<long, bool>>> MultiSetCountCompleted;

        public void MultiSetCountAsync(IDictionary<long, int> map, object userState)
        {
            AsyncOperation op = AsyncOperationManager.CreateOperation(userState);
            IAsyncResult opAr = BeginMultiSetCount(
                map,
                (ar) => { SetupAsyncCompletion<Dictionary<long, bool>, Dictionary<long, bool>>(ar, EndMultiSetCount, OnMultiSetCountCompleted); },
                op);
        }

        protected virtual void OnMultiSetCountCompleted(object sender, AsyncCompletedEventArgs<Dictionary<long, bool>> e)
        {
            var eh = MultiSetCountCompleted;

            if (null != eh)
                eh(sender, e);
        }

        public IAsyncResult BeginMultiSetCount(IDictionary<long, int> map, AsyncCallback callback, object state)
        {
            if (map == null) throw new ArgumentNullException("map");

            var args = new Dictionary<string, string>();
            args.Add("ids", map.ToDictionary(e => e.Key.ToString(), e => e.Value.ToString()).ToJsonAssociativeArray());

            var myAr = new LazyAsyncResult<Dictionary<long, bool>>(null, callback, state);
            BeginExecuteApiCall(
                @"dashboard.multiSetCount", args, false, false,
                SafeXmlDeserializeCallback<Schema.Dashboard.MultiSetCountResponse, Dictionary<long, bool>>(resp => resp.Elements.ToDictionary(e => e.Key, e => e.Value)),
                myAr);
            return myAr;
        }

        public Dictionary<long, bool> EndMultiSetCount(IAsyncResult ar)
        {
            return ar.End<Dictionary<long, bool>>();
        }

        public event EventHandler<AsyncCompletedEventArgs<Dictionary<long, bool>>> MultiIncrementCountCompleted;

        public void MultiIncrementCountAsync(IEnumerable<long> uids, object userState)
        {
            AsyncOperation op = AsyncOperationManager.CreateOperation(userState);
            IAsyncResult opAr = BeginMultiIncrementCount(
                uids,
                (ar) => { SetupAsyncCompletion<Dictionary<long, bool>, Dictionary<long, bool>>(ar, EndMultiIncrementCount, OnMultiIncrementCountCompleted); },
                op);
        }

        protected virtual void OnMultiIncrementCountCompleted(object sender, AsyncCompletedEventArgs<Dictionary<long, bool>> e)
        {
            var eh = MultiIncrementCountCompleted;

            if (null != eh)
                eh(sender, e);
        }

        public IAsyncResult BeginMultiIncrementCount(IEnumerable<long> uids, AsyncCallback callback, object state)
        {
            if (uids == null) throw new ArgumentNullException("uids");

            var args = new Dictionary<string, string>();
            args.Add("uids", '[' + string.Join(",", uids.Select(u => u.ToString()).ToArray()) + ']');

            var myAr = new LazyAsyncResult<Dictionary<long, bool>>(null, callback, state);
            BeginExecuteApiCall(
                @"dashboard.multiIncrementCount", args, false, false,
                SafeXmlDeserializeCallback<Schema.Dashboard.MultiIncrementCountResponse, Dictionary<long, bool>>(resp => resp.Elements.ToDictionary(e => e.Key, e => e.Value)),
                myAr);
            return myAr;
        }

        public Dictionary<long, bool> EndMultiIncrementCount(IAsyncResult ar)
        {
            return ar.End<Dictionary<long, bool>>();
        }

        public event EventHandler<AsyncCompletedEventArgs<Dictionary<long, bool>>> MultiDecrementCountCompleted;

        public void MultiDecrementCountAsync(IEnumerable<long> uids, object userState)
        {
            AsyncOperation op = AsyncOperationManager.CreateOperation(userState);
            IAsyncResult opAr = BeginMultiDecrementCount(
                uids,
                (ar) => { SetupAsyncCompletion<Dictionary<long, bool>, Dictionary<long, bool>>(ar, EndMultiDecrementCount, OnMultiDecrementCountCompleted); },
                op);
        }

        protected virtual void OnMultiDecrementCountCompleted(object sender, AsyncCompletedEventArgs<Dictionary<long, bool>> e)
        {
            var eh = MultiDecrementCountCompleted;

            if (null != eh)
                eh(sender, e);
        }

        public IAsyncResult BeginMultiDecrementCount(IEnumerable<long> uids, AsyncCallback callback, object state)
        {
            if (uids == null) throw new ArgumentNullException("uids");

            var args = new Dictionary<string, string>();
            args.Add("uids", uids.Select(u => u.ToString()).ToJsonArray());

            var myAr = new LazyAsyncResult<Dictionary<long, bool>>(null, callback, state);
            BeginExecuteApiCall(
                @"dashboard.multiDecrementCount", args, false, false,
                SafeXmlDeserializeCallback<Schema.Dashboard.MultiDecrementCountResponse, Dictionary<long, bool>>(resp => resp.Elements.ToDictionary(e => e.Key, e => e.Value)),
                myAr);
            return myAr;
        }

        public Dictionary<long, bool> EndMultiDecrementCount(IAsyncResult ar)
        {
            return ar.End<Dictionary<long, bool>>();
        }

        #endregion

        #region Single News

        public event EventHandler<AsyncCompletedEventArgs<long>> AddNewsCompleted;

        public void AddNewsAsync(NewsItem item, object userState)
        {
            AssertUserId();
            AddNewsAsync(UserId.Value, item, userState);
        }

        public void AddNewsAsync(long uid, NewsItem item, object userState)
        {
            AsyncOperation op = AsyncOperationManager.CreateOperation(userState);
            IAsyncResult opAr = BeginAddNews(
                uid,
                item,
                (ar) => { SetupAsyncCompletion<Int64State, long>(ar, EndAddNews, OnAddNewsCompleted); },
                op);
        }

        protected virtual void OnAddNewsCompleted(object sender, AsyncCompletedEventArgs<long> e)
        {
            var eh = AddNewsCompleted;

            if (null != eh)
                eh(sender, e);
        }

        public IAsyncResult BeginAddNews(NewsItem item, AsyncCallback callback, object state)
        {
            AssertUserId();
            return BeginAddNews(UserId.Value, item, callback, state);
        }

        public IAsyncResult BeginAddNews(long uid, NewsItem item, AsyncCallback callback, object state)
        {
            if (item == null) throw new ArgumentNullException("item");
            if (item.News == null) throw new ArgumentNullException("item.News");
            int cnt = item.News.Count;
            if (cnt > 8 || cnt < 1) throw new ArgumentException("It is required to post at least one or no more than eight news at once", "news");

            var args = new Dictionary<string, string>();
            args.Add("uid", uid.ToString());
            args.Add("news", item.News.Select(n => n.ToJson()).ToJsonArray());
            if (!String.IsNullOrEmpty(item.Image))
                args.Add("image", item.Image);

            var myAr = new LazyAsyncResult<Int64State>(new Int64State(), callback, state);
            BeginExecuteApiCall(@"dashboard.AddNews", args, false, false, Int64StateCallback, myAr);
            return myAr;
        }

        public long EndAddNews(IAsyncResult ar)
        {
            return ar.End<Int64State>().Result;
        }

        public event EventHandler<AsyncCompletedEventArgs<Dictionary<long, bool>>> ClearNewsCompleted;

        public void ClearNewsAsync(object userState)
        {
            ClearNewsAsync(null, userState);
        }

        public void ClearNewsAsync(IEnumerable<long> newsIds, object userState)
        {
            AssertUserId();
            ClearNewsAsync(UserId.Value, newsIds, userState);
        }

        public void ClearNewsAsync(long uid, IEnumerable<long> newsIds, object userState)
        {
            AsyncOperation op = AsyncOperationManager.CreateOperation(userState);
            IAsyncResult opAr = BeginClearNews(
                uid,
                newsIds,
                (ar) => { SetupAsyncCompletion<Dictionary<long, bool>, Dictionary<long, bool>>(ar, EndClearNews, OnClearNewsCompleted); },
                op);
        }

        protected virtual void OnClearNewsCompleted(object sender, AsyncCompletedEventArgs<Dictionary<long, bool>> e)
        {
            var eh = ClearNewsCompleted;

            if (null != eh)
                eh(sender, e);
        }

        public IAsyncResult BeginClearNews(AsyncCallback callback, object state)
        {
            AssertUserId();
            return BeginClearNews(UserId.Value, null, callback, state);
        }

        public IAsyncResult BeginClearNews(IEnumerable<long> newsIds, AsyncCallback callback, object state)
        {
            AssertUserId();
            return BeginClearNews(UserId.Value, newsIds, callback, state);
        }

        public IAsyncResult BeginClearNews(long uid, IEnumerable<long> newsIds, AsyncCallback callback, object state)
        {
            var args = new Dictionary<string, string>();
            args.Add("uid", uid.ToString());
            if (newsIds != null)
                args.Add("news_ids", newsIds.Select(id => id.ToString()).ToJsonArray());

            var myAr = new LazyAsyncResult<Dictionary<long, bool>>(null, callback, state);
            BeginExecuteApiCall(
                @"dashboard.clearNews", args, false, false,
                SafeXmlDeserializeCallback<Schema.Dashboard.ClearNewsResponse, Dictionary<long, bool>>(resp => resp.Elements == null ? null : resp.Elements.ToDictionary(e => e.Key, e => e.Value)),
                myAr);
            return myAr;
        }

        public Dictionary<long, bool> EndClearNews(IAsyncResult ar)
        {
            return ar.End<Dictionary<long, bool>>();
        }

        public event EventHandler<AsyncCompletedEventArgs<Dictionary<long, NewsItem>>> GetNewsCompleted;

        public void GetNewsAsync(object userState)
        {
            GetNewsAsync(null, userState);
        }

        public void GetNewsAsync(IEnumerable<long> newsIds, object userState)
        {
            AssertUserId();
            GetNewsAsync(UserId.Value, null, userState);
        }

        public void GetNewsAsync(long uid, IEnumerable<long> newsIds, object userState)
        {
            AsyncOperation op = AsyncOperationManager.CreateOperation(userState);
            IAsyncResult opAr = BeginGetNews(
                uid,
                newsIds,
                (ar) => { SetupAsyncCompletion<Dictionary<long, NewsItem>, Dictionary<long, NewsItem>>(ar, EndGetNews, OnGetNewsCompleted); },
                op);
        }

        protected virtual void OnGetNewsCompleted(object sender, AsyncCompletedEventArgs<Dictionary<long, NewsItem>> e)
        {
            var eh = GetNewsCompleted;

            if (null != eh)
                eh(sender, e);
        }

        public IAsyncResult BeginGetNews(AsyncCallback callback, object state)
        {
            AssertUserId();
            return BeginGetNews(UserId.Value, null, callback, state);
        }

        public IAsyncResult BeginGetNews(IEnumerable<long> newsIds, AsyncCallback callback, object state)
        {
            AssertUserId();
            return BeginGetNews(UserId.Value, newsIds, callback, state);
        }

        public IAsyncResult BeginGetNews(long uid, IEnumerable<long> newsIds, AsyncCallback callback, object state)
        {
            var args = new Dictionary<string, string>();
            args.Add("uid", uid.ToString());
            if (newsIds != null)
                args.Add("news_ids", newsIds.Select(id => id.ToString()).ToJsonArray());
            args.Add("format", "json");
            var myAr = new LazyAsyncResult<Dictionary<long, NewsItem>>(null, callback, state);
            BeginExecuteApiCall(
                @"dashboard.getNews", args, false, false,
                SafeJsonDeserializeCallback<Dictionary<string, NewsItem>, Dictionary<long, NewsItem>>(resp => resp.ToDictionary(kv => Int64.Parse(kv.Key), kv => kv.Value)),
                myAr);
            return myAr;
        }

        public Dictionary<long, NewsItem> EndGetNews(IAsyncResult ar)
        {
            return ar.End<Dictionary<long, NewsItem>>();
        }

        #endregion

        #region Global News

        public event EventHandler<AsyncCompletedEventArgs<long>> AddGlobalNewsCompleted;

        public void AddGlobalNewsAsync(NewsItem item, object userState)
        {
            AsyncOperation op = AsyncOperationManager.CreateOperation(userState);
            IAsyncResult opAr = BeginAddGlobalNews(
                item,
                (ar) => { SetupAsyncCompletion<Int64State, long>(ar, EndAddGlobalNews, OnAddGlobalNewsCompleted); },
                op);
        }

        protected virtual void OnAddGlobalNewsCompleted(object sender, AsyncCompletedEventArgs<long> e)
        {
            var eh = AddGlobalNewsCompleted;

            if (null != eh)
                eh(sender, e);
        }

        public IAsyncResult BeginAddGlobalNews(NewsItem item, AsyncCallback callback, object state)
        {
            if (item == null) throw new ArgumentNullException("item");
            if (item.News == null) throw new ArgumentNullException("item.News");
            int cnt = item.News.Count;
            if (cnt > 8 || cnt < 1) throw new ArgumentException("It is required to post at least one or no more than eight GlobalNews at once", "GlobalNews");

            var args = new Dictionary<string, string>();
            args.Add("news", item.News.Select(n => n.ToJson()).ToJsonArray());
            if (!String.IsNullOrEmpty(item.Image))
                args.Add("image", item.Image);

            var myAr = new LazyAsyncResult<Int64State>(new Int64State(), callback, state);
            BeginExecuteApiCall(@"dashboard.addGlobalNews", args, false, false, Int64StateCallback, myAr);
            return myAr;
        }

        public long EndAddGlobalNews(IAsyncResult ar)
        {
            return ar.End<Int64State>().Result;
        }

        public event EventHandler<AsyncCompletedEventArgs<Dictionary<long, bool>>> ClearGlobalNewsCompleted;

        public void ClearGlobalNewsAsync(object userState)
        {
            ClearGlobalNewsAsync(null, userState);
        }

        public void ClearGlobalNewsAsync(IEnumerable<long> newsIds, object userState)
        {
            AsyncOperation op = AsyncOperationManager.CreateOperation(userState);
            IAsyncResult opAr = BeginClearGlobalNews(
                newsIds,
                (ar) => { SetupAsyncCompletion<Dictionary<long, bool>, Dictionary<long, bool>>(ar, EndClearGlobalNews, OnClearGlobalNewsCompleted); },
                op);
        }

        protected virtual void OnClearGlobalNewsCompleted(object sender, AsyncCompletedEventArgs<Dictionary<long, bool>> e)
        {
            var eh = ClearGlobalNewsCompleted;

            if (null != eh)
                eh(sender, e);
        }

        public IAsyncResult BeginClearGlobalNews(AsyncCallback callback, object state)
        {
            return BeginClearGlobalNews(null, callback, state);
        }

        public IAsyncResult BeginClearGlobalNews(IEnumerable<long> newsIds, AsyncCallback callback, object state)
        {
            var args = new Dictionary<string, string>();
            if (newsIds != null)
                args.Add("news_ids", newsIds.Select(id => id.ToString()).ToJsonArray());

            var myAr = new LazyAsyncResult<Dictionary<long, bool>>(null, callback, state);
            BeginExecuteApiCall(
                @"dashboard.clearGlobalNews", args, false, false,
                SafeXmlDeserializeCallback<Schema.Dashboard.ClearGlobalNewsResponse, Dictionary<long, bool>>(resp => resp.Elements == null ? null : resp.Elements.ToDictionary(e => e.Key, e => e.Value)),
                myAr);
            return myAr;
        }

        public Dictionary<long, bool> EndClearGlobalNews(IAsyncResult ar)
        {
            return ar.End<Dictionary<long, bool>>();
        }

        public event EventHandler<AsyncCompletedEventArgs<Dictionary<long, NewsItem>>> GetGlobalNewsCompleted;

        public void GetGlobalNewsAsync(object userState)
        {
            GetGlobalNewsAsync(null, userState);
        }

        public void GetGlobalNewsAsync(IEnumerable<long> newsIds, object userState)
        {
            AsyncOperation op = AsyncOperationManager.CreateOperation(userState);
            IAsyncResult opAr = BeginGetGlobalNews(
                newsIds,
                (ar) => { SetupAsyncCompletion<Dictionary<long, NewsItem>, Dictionary<long, NewsItem>>(ar, EndGetGlobalNews, OnGetGlobalNewsCompleted); },
                op);
        }

        protected virtual void OnGetGlobalNewsCompleted(object sender, AsyncCompletedEventArgs<Dictionary<long, NewsItem>> e)
        {
            var eh = GetGlobalNewsCompleted;

            if (null != eh)
                eh(sender, e);
        }

        public IAsyncResult BeginGetGlobalNews(AsyncCallback callback, object state)
        {
            return BeginGetGlobalNews(null, callback, state);
        }

        public IAsyncResult BeginGetGlobalNews(IEnumerable<long> newsIds, AsyncCallback callback, object state)
        {
            var args = new Dictionary<string, string>();
            if (newsIds != null)
                args.Add("news_ids", newsIds.Select(id => id.ToString()).ToJsonArray());
            args.Add("format", "json");
            var myAr = new LazyAsyncResult<Dictionary<long, NewsItem>>(null, callback, state);
            BeginExecuteApiCall(
                @"dashboard.getGlobalNews", args, false, false,
                SafeJsonDeserializeCallback<Dictionary<string, NewsItem>, Dictionary<long, NewsItem>>(resp => resp.ToDictionary(kv => Int64.Parse(kv.Key), kv => kv.Value)),
                myAr);
            return myAr;
        }

        public Dictionary<long, NewsItem> EndGetGlobalNews(IAsyncResult ar)
        {
            return ar.End<Dictionary<long, NewsItem>>();
        }

        #endregion

        #region Multi News

        public event EventHandler<AsyncCompletedEventArgs<Dictionary<long, long>>> MultiAddNewsCompleted;

        public void MultiAddNewsAsync(IEnumerable<long> uids, NewsItem item, object userState)
        {
            AsyncOperation op = AsyncOperationManager.CreateOperation(userState);
            IAsyncResult opAr = BeginMultiAddNews(
                uids,
                item,
                (ar) => { SetupAsyncCompletion<Dictionary<long, long>, Dictionary<long, long>>(ar, EndMultiAddNews, OnMultiAddNewsCompleted); },
                op);
        }

        protected virtual void OnMultiAddNewsCompleted(object sender, AsyncCompletedEventArgs<Dictionary<long, long>> e)
        {
            var eh = MultiAddNewsCompleted;

            if (null != eh)
                eh(sender, e);
        }

        public IAsyncResult BeginMultiAddNews(IEnumerable<long> uids, NewsItem item, AsyncCallback callback, object state)
        {
            if (item == null) throw new ArgumentNullException("item");
            if (item.News == null) throw new ArgumentNullException("item.News");
            int cnt = item.News.Count;
            if (cnt > 8 || cnt < 1) throw new ArgumentException("It is required to post at least one or no more than eight news at once", "news");

            var args = new Dictionary<string, string>();
            args.Add("uids", uids.Select(u => u.ToString()).ToJsonArray());
            args.Add("news", item.News.Select(n => n.ToJson()).ToJsonArray());
            if (!String.IsNullOrEmpty(item.Image))
                args.Add("image", item.Image);

            var myAr = new LazyAsyncResult<Dictionary<long, long>>(null, callback, state);
            BeginExecuteApiCall(@"dashboard.multiAddNews", args, false, false,
                SafeXmlDeserializeCallback<Schema.Dashboard.MultiAddNewsResponse, Dictionary<long, long>>(resp => resp.Elements == null ? null : resp.Elements.ToDictionary(e => e.Key, e => e.Value)),
                myAr);
            return myAr;
        }

        public Dictionary<long, long> EndMultiAddNews(IAsyncResult ar)
        {
            return ar.End<Dictionary<long, long>>();
        }

        public event EventHandler<AsyncCompletedEventArgs<Dictionary<long, Dictionary<long, bool>>>> MultiClearNewsCompleted;

        public void MultiClearNewsAsync(Dictionary<long, IEnumerable<long>> ids, object userState)
        {
            AsyncOperation op = AsyncOperationManager.CreateOperation(userState);
            IAsyncResult opAr = BeginMultiClearNews(
                ids,
                (ar) => { SetupAsyncCompletion<Dictionary<long, Dictionary<long, Dictionary<long, bool>>>, Dictionary<long, Dictionary<long, bool>>>(ar, EndMultiClearNews, OnMultiClearNewsCompleted); },
                op);
        }

        protected virtual void OnMultiClearNewsCompleted(object sender, AsyncCompletedEventArgs<Dictionary<long, Dictionary<long, bool>>> e)
        {
            var eh = MultiClearNewsCompleted;

            if (null != eh)
                eh(sender, e);
        }

        public IAsyncResult BeginMultiClearNews(Dictionary<long, IEnumerable<long>> ids, AsyncCallback callback, object state)
        {
            var args = new Dictionary<string, string>();
            args.Add("ids", ids.ToDictionary(u => u.Key.ToString(), u => u.Value == null ? "[]" : u.Value.Select(i => i.ToString()).ToJsonArray()).ToJsonAssociativeArray());

            var myAr = new LazyAsyncResult<Dictionary<long, Dictionary<long, bool>>>(null, callback, state);
            BeginExecuteApiCall(
                @"dashboard.multiClearNews", args, false, false,
                SafeXmlDeserializeCallback<Schema.Dashboard.MultiClearNewsResponse, Dictionary<long, Dictionary<long, bool>>>(resp => resp.Elements == null ? null : resp.Elements.ToDictionary(u => u.Key, u => u.Elements.ToDictionary(k => k.Key, k => k.Value))),
                myAr);
            return myAr;
        }

        public Dictionary<long, Dictionary<long, bool>> EndMultiClearNews(IAsyncResult ar)
        {
            return ar.End<Dictionary<long, Dictionary<long, bool>>>();
        }

        public event EventHandler<AsyncCompletedEventArgs<Dictionary<long, Dictionary<long, NewsItem>>>> MultiGetNewsCompleted;

        public void MultiGetNewsAsync(Dictionary<long, IEnumerable<long>> ids, object userState)
        {
            AsyncOperation op = AsyncOperationManager.CreateOperation(userState);
            IAsyncResult opAr = BeginMultiGetNews(
                ids,
                (ar) => { SetupAsyncCompletion<Dictionary<long, Dictionary<long, NewsItem>>, Dictionary<long, Dictionary<long, NewsItem>>>(ar, EndMultiGetNews, OnMultiGetNewsCompleted); },
                op);
        }

        protected virtual void OnMultiGetNewsCompleted(object sender, AsyncCompletedEventArgs<Dictionary<long, Dictionary<long, NewsItem>>> e)
        {
            var eh = MultiGetNewsCompleted;

            if (null != eh)
                eh(sender, e);
        }

        public IAsyncResult BeginMultiGetNews(Dictionary<long, IEnumerable<long>> ids, AsyncCallback callback, object state)
        {
            var args = new Dictionary<string, string>();
            args.Add("ids", ids.ToDictionary(u => u.Key.ToString(), u => u.Value == null ? "[]" : u.Value.Select(i => i.ToString()).ToJsonArray()).ToJsonAssociativeArray());
            args.Add("format", "json");
            var myAr = new LazyAsyncResult<Dictionary<long, Dictionary<long, NewsItem>>>(null, callback, state);
            BeginExecuteApiCall(
                @"dashboard.multiGetNews", args, false, false,
                SafeJsonDeserializeCallback<Dictionary<string, Dictionary<string, NewsItem>>, Dictionary<long, Dictionary<long, NewsItem>>>(resp => resp.ToDictionary(kv => Int64.Parse(kv.Key), kv => kv.Value.ToDictionary(u => Int64.Parse(u.Key), u => u.Value))),
                myAr);
            return myAr;
        }

        public Dictionary<long, Dictionary<long, NewsItem>> EndMultiGetNews(IAsyncResult ar)
        {
            return ar.End<Dictionary<long, Dictionary<long, NewsItem>>>();
        }

        #endregion

        #region Activities

        public event EventHandler<AsyncCompletedEventArgs<Dictionary<long, bool>>> RemoveActivityCompleted;

        public void RemoveActivityAsync(IEnumerable<long> activityIds, object userState)
        {
            AsyncOperation op = AsyncOperationManager.CreateOperation(userState);
            IAsyncResult opAr = BeginRemoveActivity(
                activityIds,
                (ar) => { SetupAsyncCompletion<Dictionary<long, bool>, Dictionary<long, bool>>(ar, EndRemoveActivity, OnRemoveActivityCompleted); },
                op);
        }

        protected virtual void OnRemoveActivityCompleted(object sender, AsyncCompletedEventArgs<Dictionary<long, bool>> e)
        {
            var eh = RemoveActivityCompleted;

            if (null != eh)
                eh(sender, e);
        }

        public IAsyncResult BeginRemoveActivity(IEnumerable<long> activityIds, AsyncCallback callback, object state)
        {
            AssertActiveSession();
            if (activityIds == null) throw new ArgumentNullException("activityIds");
            if (!activityIds.Any()) throw new ArgumentException("May not be empty", "activityIds");

            var args = new Dictionary<string, string>();
            args.Add("activity_ids", activityIds.Select(id => id.ToString()).ToJsonArray());

            var myAr = new LazyAsyncResult<Dictionary<long, bool>>(null, callback, state);
            BeginExecuteApiCall(
                @"dashboard.removeActivity", args, true, false,
                SafeXmlDeserializeCallback<Schema.Dashboard.RemoveActivityResponse, Dictionary<long, bool>>(resp => resp.Elements == null ? null : resp.Elements.ToDictionary(e => e.Key, e => e.Value)),
                myAr);
            return myAr;
        }

        public Dictionary<long, bool> EndRemoveActivity(IAsyncResult ar)
        {
            return ar.End<Dictionary<long, bool>>();
        }

        public event EventHandler<AsyncCompletedEventArgs<long>> PublishActivityCompleted;

        public void PublishActivityAsync(News news, object userState)
        {
            AsyncOperation op = AsyncOperationManager.CreateOperation(userState);
            IAsyncResult opAr = BeginPublishActivity(
                news,
                (ar) => { SetupAsyncCompletion<Int64State, long>(ar, EndPublishActivity, OnPublishActivityCompleted); },
                op);
        }

        protected virtual void OnPublishActivityCompleted(object sender, AsyncCompletedEventArgs<long> e)
        {
            var eh = PublishActivityCompleted;

            if (null != eh)
                eh(sender, e);
        }

        public IAsyncResult BeginPublishActivity(News news, AsyncCallback callback, object state)
        {
            AssertActiveSession();
            if (news == null) throw new ArgumentNullException("news");

            var args = new Dictionary<string, string>();
            args.Add("activity", news.ToJson());

            var myAr = new LazyAsyncResult<Int64State>(new Int64State(), callback, state);
            BeginExecuteApiCall(@"dashboard.publishActivity", args, true, false, Int64StateCallback, myAr);
            return myAr;
        }

        public long EndPublishActivity(IAsyncResult ar)
        {
            return ar.End<Int64State>().Result;
        }

        public event EventHandler<AsyncCompletedEventArgs<Dictionary<long, News>>> GetActivityCompleted;

        public void GetActivityAsync(object userState)
        {
            GetActivityAsync(null, userState);
        }

        public void GetActivityAsync(IEnumerable<long> activityIds, object userState)
        {
            AsyncOperation op = AsyncOperationManager.CreateOperation(userState);
            IAsyncResult opAr = BeginGetActivity(
                activityIds,
                (ar) => { SetupAsyncCompletion<Dictionary<long, News>, Dictionary<long, News>>(ar, EndGetActivity, OnGetActivityCompleted); },
                op);
        }

        protected virtual void OnGetActivityCompleted(object sender, AsyncCompletedEventArgs<Dictionary<long, News>> e)
        {
            var eh = GetActivityCompleted;

            if (null != eh)
                eh(sender, e);
        }

        public IAsyncResult BeginGetActivity(AsyncCallback callback, object state)
        {
            return BeginGetActivity(null, callback, state);
        }

        public IAsyncResult BeginGetActivity(IEnumerable<long> activityIds, AsyncCallback callback, object state)
        {
            AssertActiveSession();
            var args = new Dictionary<string, string>();
            if (activityIds != null)
                args.Add("activity_ids", activityIds.Select(id => id.ToString()).ToJsonArray());
            args.Add("format", "json");
            var myAr = new LazyAsyncResult<Dictionary<long, News>>(null, callback, state);
            BeginExecuteApiCall(
                @"dashboard.getActivity", args, true, false,
                SafeJsonDeserializeCallback<Dictionary<string, News>, Dictionary<long, News>>(resp => resp.ToDictionary(kv => Int64.Parse(kv.Key), kv => kv.Value)),
                myAr);
            return myAr;
        }

        public Dictionary<long, News> EndGetActivity(IAsyncResult ar)
        {
            return ar.End<Dictionary<long, News>>();
        }

        #endregion

        #endregion
    }
}
